package com.zjlab.web.config;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 将controller的入参出参和耗时打印
 *
 * @author xue
 * @create 2022-11-03 9:36
 */
@Slf4j
@Aspect
@Component
public class RequestAspect {

    private static final ReentrantLock LOCK = new ReentrantLock();

    @Pointcut("execution(* com.zjlab.web.controller..*.*(..)))")
    public void logPointCut() {
    }


    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = point.proceed();
        long costTime = System.currentTimeMillis() - startTime;
        recordLog(point, costTime, result);
        return result;
    }

    private void recordLog(ProceedingJoinPoint joinPoint, long time, Object result) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = signature.getName();

        //请求的参数
        Object[] args = joinPoint.getArgs();
        Stream<?> stream = ObjectUtils.isEmpty(args) ? Stream.empty() : Arrays.stream(args);
        List<Object> logArgs =
                stream.filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse))).collect(Collectors.toList());
        String paramsJson = JSONUtil.toJsonStr(logArgs);
        String resultJson = JSONUtil.toJsonStr(result);

        LOCK.lock();
        try {
            log.info(">>>>>>>>>>请求开始>>>>>>>>>>");
            log.info("请求方法:{}", className + "=>" + methodName + "()");
            log.info("请求参数:{}", paramsJson);
            log.info("返回值:{}", resultJson);
            log.info("耗时: {} ms", time);
            log.info("<<<<<<<<<<请求结束<<<<<<<<<<");
        } finally {
            LOCK.unlock();
        }

    }


}
